﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;

using Swaf;
using Swaf.BizObj;
using Swaf.BizRule;

namespace PageEditing
{
	public class PageEditBizRules : Syrinx.BaseBizRules
	{
		public IBizObjList getPagesAvailableForEditing(IApplication app, IRuleContext context)
		{
			IBizObjList pages = app.bizObjMgr.createList("StandAloneArticleListPageInfo");

			string dirName = getBaseDir(app,true);
			int accountForBar = 1;
			if (dirName.EndsWith(Path.DirectorySeparatorChar.ToString()))
				accountForBar = 0;
			string[] fileNames = Directory.GetFiles(dirName, "*.aspx");
			foreach (string fileName in fileNames)
			{
				bool addPage = true;
				string pageName = fileName.Substring(dirName.Length + accountForBar);
				foreach (string sysPage in s_systemPageNames)
					if (string.Compare(sysPage, pageName, true) == 0)
					{
						addPage = false;
						break;
					}
				if (addPage)
				{
					IBizObj pageInfo = pages.insertNew();
					pageInfo.put("pageName", pageName);
					pageInfo.isNew = false;
					pageInfo.clearDirtyFlags();
				}
			}

			return pages;
		}

		static string[] s_systemPageNames = new string[] { "AjaxRequestHandler.aspx", "NitobiLiveStreamHandler.aspx" };

		static Regex s_pageInfoComment = new Regex(@"<%--[^T]*Template:\s*([^\s]+).*--%>");
		static Regex s_pageTitle = new Regex(@"public string TitleFormat = ""([^""]+)"";");
		static Regex s_pageAppFun = new Regex(@"<%.*?SecurityPrivilege\s*=\s*""([^""]*)"";.*%>");
		static Regex s_pageSecLevel = new Regex(@"<%.*?RequiredPrivilegeLevel\s*=\s*Swaf.Security.Privileges.([^;]+);.*%>");
		public IBizObj getPageEditorDetails(IApplication app, IRuleContext context, string pageName)
		{
			IBizObj page = app.bizObjMgr.create("StandAloneArticleListPageInfo");
			page.put("pageName", pageName);
			string pageShortName = pageName;
			if (pageShortName.EndsWith(".aspx", StringComparison.CurrentCultureIgnoreCase))
				pageShortName = pageShortName.Substring(0, pageShortName.Length - 5);
			page.put("pageShortName", pageShortName);

			string baseDir = getBaseDir(app,true);
			string fullPageName = Cmn.pathCombine(baseDir, pageName);

			if (File.Exists(fullPageName))
			{
				string pageContents = File.ReadAllText(fullPageName);
				Match m = s_pageInfoComment.Match(pageContents);
				if (m.Success)
					page.put("baseTemplate", m.Groups[1].Value.Trim('\\'));
				m = s_pageTitle.Match(pageContents);
				if (m.Success)
					page.put("title", m.Groups[1].Value);
				m = s_pageAppFun.Match(pageContents);
				if(m.Success)
				{
					string appFun = m.Groups[1].Value;
					if(appFun.StartsWith("AppFunctions."))
						appFun = appFun.Substring("AppFunctions.".Length);
					page.put("securityAppFunction", appFun);
				}
				m = s_pageSecLevel.Match(pageContents);
				if (m.Success)
					try
					{
						page.put("securityLevel", (int)(Swaf.Security.Privileges)Enum.Parse(typeof(Swaf.Security.Privileges),m.Groups[1].Value, true));
					}
					catch(Exception e)
					{
					//Invalid security level provided.
					}				
			}

			page.isNew = false;
			page.clearDirtyFlags();
			return page;
		}

		public IBizObjList getAvailablePageTemplates(IApplication app, IRuleContext context)
		{
			IBizObjList pages = app.bizObjMgr.createList("StandAloneArticleListPageInfo");

			string dirName = Cmn.pathCombine(getBaseDir(app, false), "_PageTemplates");
			if (Directory.Exists(dirName))
			{
				string[] fileNames = Directory.GetFiles(dirName, "*.aspx");
				foreach (string fileName in fileNames)
				{
					IBizObj pageInfo = pages.insertNew();
					pageInfo.put("pageName", fileName.Substring(dirName.Length+1));
				}
			}
			return pages;
		}

		public IBizObj updateEditedPage(IApplication app, IRuleContext context, IBizObj pageInfo)
		{
			string baseDir = getBaseDir(app,true);
			string pageName = (string)pageInfo.get("pageShortName");
			if (!pageName.EndsWith(".aspx", StringComparison.CurrentCultureIgnoreCase))
				pageName += ".aspx";
			string fullPageName = Cmn.pathCombine(baseDir, pageName);
			string pageContents= null;
			IResults rc = null;
			Match m = null;

			if (pageInfo.isNew || pageInfo.isDirty("baseTemplate"))
			{
				string dirName = Cmn.pathCombine(getBaseDir(app, false), "_PageTemplates");
				if (Directory.Exists(dirName))
				{
					string templatePage = Cmn.pathCombine(dirName, (string)pageInfo.get("baseTemplate"));
					if (File.Exists(templatePage))
					{
						rc = context.RuleGroup.execute(context, "processPageTemplateUpdate", File.ReadAllText(templatePage), pageInfo);
						pageContents = rc.CallResults as string;
					}
				}
			}
			else
			{
				if (File.Exists(fullPageName))
					pageContents = File.ReadAllText(fullPageName);
			}

			if (pageContents != null)
			{
				StringBuilder newContents = new StringBuilder(pageContents.Length + 1024);
				int lastPos = 0;
				if (pageInfo.isNew || pageInfo.isDirty("baseTemplate"))
				{
					m = s_pageInfoComment.Match(pageContents);
					if (m.Success)
					{
						newContents.Append(pageContents.Substring(lastPos, m.Groups[1].Index - lastPos));
						newContents.Append(pageInfo.get("baseTemplate"));
						lastPos = m.Groups[1].Index + m.Groups[1].Length;
					}
				}

				m = s_pageTitle.Match(pageContents);
				if (m.Success)
				{
					newContents.Append(pageContents.Substring(lastPos, m.Groups[1].Index - lastPos));
					newContents.Append(pageInfo.get("title"));
					lastPos = m.Groups[1].Index + m.Groups[1].Length;
				}

				m = s_pageAppFun.Match(pageContents);
				if (m.Success)
				{
					newContents.Append(pageContents.Substring(lastPos, m.Groups[1].Index - lastPos));
					newContents.Append("AppFunctions.").Append(pageInfo.get("securityAppFunction"));
					lastPos = m.Groups[1].Index + m.Groups[1].Length;
				}

				m = s_pageSecLevel.Match(pageContents);
				if (m.Success)
				{
					newContents.Append(pageContents.Substring(lastPos, m.Groups[1].Index - lastPos));
					newContents.Append(((Swaf.Security.Privileges)pageInfo.get("securityLevel")).ToString());
					lastPos = m.Groups[1].Index + m.Groups[1].Length;
				}

				//Overwrite page with new contents
				newContents.Append(pageContents.Substring(lastPos));
				File.WriteAllText(fullPageName, newContents.ToString());
			}

			rc = context.RuleGroup.execute(context, "getPageEditorDetails", pageInfo.get("pageName"));
			IBizObj updatedPage = rc.CallResults as IBizObj;

			return updatedPage;
		}

		public string processPageTemplateUpdate(IApplication app, IRuleContext context, string templateContent, IBizObj pageInfo)
		{
			return templateContent;
		}

		public void deletedEditedPage(IApplication app, IRuleContext context, string pageName)
		{
		}

		protected static Regex s_previewSalMarker = new Regex("<!--.*?SalArea.*?-->");
		public string createSalPreviewPage(IApplication app, IRuleContext context, IBizObj salObj)
		{
			string previewUrl = "";
			string baseDir = getBaseDir(app,true);
			string basePreviewPage = Cmn.pathCombine(baseDir, "std", "SalPreviewTemplate.aspx");
			if (File.Exists(basePreviewPage))
			{
				string previewContent = File.ReadAllText(basePreviewPage);
				MatchCollection mc = s_previewSalMarker.Matches(previewContent);
				if (mc.Count == 2)
				{
					StringBuilder buff = new StringBuilder(previewContent.Length + 512);
					buff.Append(previewContent.Substring(0, mc[0].Index));
					buff.Append(SalPageEditBizRules.convertSalObjToHtml(salObj));
					buff.Append(previewContent.Substring(mc[1].Index + mc[1].Length));

					string previewDir = Cmn.pathCombine(baseDir, "_SalPreviews");
					Directory.CreateDirectory(previewDir);
					string previewPageName = string.Format("{0}.{1}.aspx", CurrentUser.get("userName"), salObj.get("id"));
					File.WriteAllText(Cmn.pathCombine(previewDir, previewPageName), buff.ToString());

					string startPath = ActiveCompany.get("parentId") == null ? "" : ("/" + (string)ActiveCompany.get("shortName"));
					previewUrl = string.Format("{0}/_SalPreviews/{1}", startPath, previewPageName);
				}
			}

			return previewUrl;
		}

		public static string getBaseDir(IApplication app, bool includeShortName)
		{
			string root = app.resMgr.resolve("$ConfigParam1$");
			string companyShortName = ActiveCompany.get("parentId") == null ? "" : (string)ActiveCompany.get("shortName");
			string dirName = includeShortName ? Cmn.pathCombine(root, companyShortName) : root;
			if (dirName.StartsWith("file:\\\\", StringComparison.CurrentCultureIgnoreCase) ||
				dirName.StartsWith("file://", StringComparison.CurrentCultureIgnoreCase))
				dirName = dirName.Substring(7);

			return dirName;
		}
	}
}
